package com.codefish.framework.spring.beans.factory;

import com.codefish.framework.spring.beans.exception.NoSuchBeanDefinitionException;
import com.codefish.framework.spring.beans.factory.config.IBeanPostProcessor;
import com.codefish.framework.spring.beans.factory.config.IConfigurableBeanFactory;
import com.codefish.framework.spring.beans.factory.support.BeanDefinition;
import com.codefish.framework.spring.beans.factory.support.DisposableBeanAdapter;
import com.codefish.framework.spring.beans.factory.support.FactoryBeanRegistrySupport;
import com.codefish.framework.spring.core.utils.LogUtils;
import com.codefish.framework.spring.core.utils.Logger;
import com.codefish.framework.spring.util.IStringValueResolver;
import com.sun.istack.internal.Nullable;

import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * 单例的BeanFactory，管理单例的bean对象
 *
 * @author <a href='https://gitee.com/hzf2281'>codefish</a>
 * @version 1.0.0
 * @since 2022/09/23 下午 03:47
 */
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements IConfigurableBeanFactory {

    private static final Logger log = LogUtils.getLogger(AbstractBeanFactory.class);

    /**
     * beanPostProcessor处理器列表
     */
    private final List<IBeanPostProcessor> beanPostProcessorList = new CopyOnWriteArrayList<>();
    /**
     * 字符串表达式解析器列表
     */
    private final List<IStringValueResolver> embeddedValueResolvers = new CopyOnWriteArrayList<>();


    @Override
    public Object getBean(String beanName) throws NoSuchBeanDefinitionException {
        String name = beanName;
        while (beanName.startsWith(FACTORY_BEAN_PREFIX)) {
            beanName = beanName.substring(FACTORY_BEAN_PREFIX.length());
        }

        Object bean;
        Object singletonInstance = getSingleton(beanName);
        BeanDefinition beanDefinition = null;

        if (singletonInstance != null) {
            //能找到bean则返回找到的bean
            bean = singletonInstance;
        } else {
            //找不到则需要进行创建bean
            beanDefinition = getBeanDefinition(beanName);
            if (beanDefinition == null) {
                throw new NoSuchBeanDefinitionException(beanName);
            }
            if (beanDefinition.isSingleton()) {
                //bean的scope为singleton，需要创建实例并注册到BeanRegistry中
                final BeanDefinition bd = beanDefinition;
                final String beanName0 = beanName;
                bean = getSingleton(beanName, () -> {
                    return createBean(beanName0, bd);
                });
            } else if (beanDefinition.isPrototype()) {
                //bean的scope为prototype，直接创建实例并返回这个实例
                bean = createBean(beanName, beanDefinition);
            } else {
                throw new RuntimeException("BeanDefinition的scope应为'singleton'或prototype'");
            }
        }

        return getObjectForBeanInstance(bean, name, beanName, beanDefinition);
    }

    @Override
    public <T> T getBean(String beanName, Class<T> requiredType) throws NoSuchBeanDefinitionException {
        //尝试获取beanName对应的bean实例
        Object bean = getBean(beanName);
        if (requiredType.isAssignableFrom(bean.getClass())) {
            return (T) bean;
        }
        return null;
    }

    @Override
    public void addBeanPostProcessor(IBeanPostProcessor beanPostProcessor) {
        //移除旧版本
        this.beanPostProcessorList.remove(beanPostProcessor);
        //添加到beanPostProcessor列表末尾
        this.beanPostProcessorList.add(beanPostProcessor);
    }

    @Override
    public void destroySingletons() {
        super.destroySingletons();
    }

    @Override
    public String resolveEmbeddedValue(String value) {
        if (value == null) {
            return null;
        }
        String result = value;
        for (IStringValueResolver resolver : embeddedValueResolvers) {
            result = resolver.resolveStringValue(result);
            if (result == null) {
                break;
            }
        }
        return result;
    }

    @Override
    public void addStringValueResolver(IStringValueResolver stringValueResolver) {
        this.embeddedValueResolvers.add(stringValueResolver);
    }

    /**
     * 注册DisposableBean
     */
    protected void registerDisposableBeanIfNecessary(String beanName, Object bean, BeanDefinition beanDefinition) {
        if (bean instanceof IDisposableBean || bean instanceof AutoCloseable) {
            if (beanDefinition.isSingleton()) {
                //只有单例的bean才需要进行销毁操作
                registerDisposableBean(beanName, new DisposableBeanAdapter(beanName, bean, beanDefinition));
            }
        }
    }

    /**
     * 获取目标bean实例
     */
    protected Object getObjectForBeanInstance(Object beanInstance, String name, String beanName, BeanDefinition beanDefinition) {
        if (!(beanInstance instanceof IFactoryBean)) {
            return beanInstance;
        }

        if (name.startsWith(FACTORY_BEAN_PREFIX)) {
            return beanInstance;
        }

        return getObjectFromFactoryBean((IFactoryBean<?>) beanInstance, beanName);
    }

    public List<IBeanPostProcessor> getBeanPostProcessorList() {
        return this.beanPostProcessorList;
    }

    /**
     * 获取对应的BeanDefinition，延迟到子类实现
     *
     * @param beanName beanName
     * @return 对应的BeanDefinition
     */
    public abstract BeanDefinition getBeanDefinition(String beanName);

    /**
     * 根据beanDefinition创建bean实例并注册到beanFactory中，延迟到子类实现
     *
     * @param beanName       beanName
     * @param beanDefinition beanDefinition
     * @param args           实例化bean时需要传给构造函数的参数
     * @return 创建完成后的bean实例
     */
    protected abstract Object createBean(String beanName, BeanDefinition beanDefinition, @Nullable Object... args);

}